# -*- coding: utf-8 -*-
#!/usr/bin/env python

import os
import sys
import wsgiref.handlers
import webapp2
import json
import time
import logging
import base64
import urllib
import random
import string
import jinja2
import cgi
import copy

from datetime import datetime, timedelta
from operator import itemgetter
from google.appengine.api import users
from google.appengine.ext.webapp import template
from google.appengine.api.logservice import logservice
from google.appengine.ext import ndb
from google.appengine.datastore.datastore_query import Cursor

import statistics
from statistics import *
from models import *
from app_global import *
from game_functions import *

ADMIN_PASSWORD = '902n302qng2q'
PAGE = 20 # 20

def rewardName(reward, amount):
	if reward<0:
		return u""
	if amount>0:
		return [u'복숭아', u'코인', u'당근',][reward] + u"({0}개)".format(amount)
	return [u'복숭아', u'코인', u'당근',][reward]

def characterName(ident):
	CHARS = getStorageData("characters")
	if ident<1:
		return u""
	return CHARS[ident-1]["name"] 

def characterInfo(c):
	CHARS = getStorageData("characters")
	return u"%s(lv.%d, exp.%d, pnt.%d)" % (CHARS[c['id']-1]["name"], c['level'], c['exp'], c['point'],)
	
def characterInfos(characters):
	CHARS = getStorageData("characters")
	names = []
	for c in characters:
		if c:
			names.append(u"%s(lv.%d, exp.%d, pnt.%d)" % (CHARS[c["id"]-1]["name"], c["level"], c["exp"], c["point"]))
	return names

def gameName(idx):
	return GAME_NAMES[idx]

class CSManageLog(ndb.Model):
	admin_name = ndb.StringProperty(required=True)
	user_id = ndb.IntegerProperty(default=0)
	action = ndb.IntegerProperty(required=True)
	value = ndb.IntegerProperty(default=0)
	desc = ndb.StringProperty(required=True)
	created_at = ndb.DateTimeProperty(auto_now_add=True)
	
class CSHandler(webapp2.RequestHandler):
	@classmethod
	def logged_in(cls, handler_method):
		def auth_required(self, *args, **kwargs):
			if (users.get_current_user() or
				self.request.headers.get('X-AppEngine-Cron')):
				handler_method(self, *args, **kwargs)
			else:
				self.error(403)
		return auth_required
	
	def get(self, userId=None):
		if not users.get_current_user() or not users.is_current_user_admin():
			self.redirect(users.create_login_url(self.request.uri))
			return		

		logoutUrl = users.create_logout_url(self.request.uri)
		adminName = users.get_current_user().nickname()
		
		maxCol = 1
		userInfos = []
		charInfos = []
		d3 = []
		w3 = []
		achievements = []
		
		if eval(str(userId)) is not None:
			user = User.get_by_id(int(userId))
			if user is None:
				userInfo = None
			else:
				logging.info('name = %s, image_url = %s' % (user.name,user.image_url,))
				try:
					#user_name = aes256_decrypt(user.name)
					user_name = aes256_decrypt_csuse(user.name)
					user_name = user_name.decode('utf-8')
				except:
					user_name = user.name
				
				try:
					#user_image = aes256_decrypt(user.image_url)
					user_image = aes256_decrypt_csuse(user.image_url)
				except:
					user_image = user.image_url
				
				user_platform = "IOS" if user.platform_id==PLATFORM_IOS else "Android"
				
				season = Season.season()
				seasonData = user.seasonData(season.count)
				
				userId = user.key.id()
				
				userInfos.append({"index":len(userInfos), "title":u"앱 ID", "content":userId})
				userInfos.append({"index":len(userInfos), "title":u"이름", "content":user_name})
				userInfos.append({"index":len(userInfos), "title":u"사진", "content":user_image, "image":True})
				userInfos.append({"index":len(userInfos), "title":u"플랫폼", "content":user_platform})
				userInfos.append({"index":len(userInfos), "title":u"복숭아", "content":user.cash})
				userInfos.append({"index":len(userInfos), "title":u"코인", "content":user.coin})
				userInfos.append({"index":len(userInfos), "title":u"당근", "content":user.bout})
				userInfos.append({"index":len(userInfos), "title":u"푸시거부", "content":user.push_blocked})
				userInfos.append({"index":len(userInfos), "title":u"당근거부", "content":user.bout_blocked})
				userInfos.append({"index":len(userInfos), "title":u"일일 포인트", "content":user.daily_point})
				userInfos.append({"index":len(userInfos), "title":u"초대 보상", "titles":range(len(user.invite_rewards)), "contents":user.invite_rewards})
				userInfos.append({"index":len(userInfos), "title":u"게임플레이", "content":user.accrue_record.play})
				userInfos.append({"index":len(userInfos), "title":u"최고 점수", "content":user.accrue_record.best_score})
				userInfos.append({"index":len(userInfos), "title":u"랭크업", "titles":[u"%d위"%(i+1) for i in range(len(user.accrue_record.rank_ups))], "contents":user.accrue_record.rank_ups})
				userInfos.append({"index":len(userInfos), "title":u"앱 초대", "content":user.accrue_record.invite})
				userInfos.append({"index":len(userInfos), "title":u"미션완료", "content":user.accrue_record.mission_completed})
				userInfos.append({"index":len(userInfos), "title":u"선물하기", "content":user.accrue_record.present})
				userInfos.append({"index":len(userInfos), "title":u"캐릭터 최고 레벨", "content":user.accrue_record.max_character_level})
				userInfos.append({"index":len(userInfos), "title":u"호감도행동", "content":user.accrue_record.character_action})
				userInfos.append({"index":len(userInfos), "title":u"호감도버프", "content":user.accrue_record.character_buff})
				userInfos.append({"index":len(userInfos), "title":u"시즌", "content":seasonData.season})
				userInfos.append({"index":len(userInfos), "title":u"(시즌)보상완료", "content":seasonData.rewarded})
				userInfos.append({"index":len(userInfos), "title":u"(시즌)게임별 점수", "titles":GAME_NAMES, "contents":seasonData.scores})
				userInfos.append({"index":len(userInfos), "title":u"(시즌)게임별 랭킹", "titles":GAME_NAMES, "contents":seasonData.ranks})
				userInfos.append({"index":len(userInfos), "title":u"(주간)출석스탬프", "content":user.daily_stamp})
				userInfos.append({"index":len(userInfos), "title":u"최근 로그인", "content":replace_timezone(user.loggedin_at, 'Asia/Seoul').strftime('%Y-%m-%d %H:%M:%S')})
				userInfos.append({"index":len(userInfos), "title":u"가입일", "content":replace_timezone(user.created_at, 'Asia/Seoul').strftime('%Y-%m-%d %H:%M:%S')})
				
				d3, w3, achievements = getUserMissions(user, Mission.todayMission())
				# 그럴일 없겠지만, getUserMissions에서 user를 수정하기 때문에, 여기에서는 user.put() 을 호출하면 안됨
				for i in range(len(d3)):
					d3[i] = {
						"index":i,
						"name":d3[i]["name"],
						"status":u"완료" if d3[i]["status"]!=-1 else u"미완료",
					}
				for i in range(len(w3)):
					w3[i] = {
						"index":i,
						"name":w3[i]["name"],
						"status":u"완료" if w3[i]["status"]!=-1 else u"미완료",
					}
				for i in range(len(achievements)):
					achievements[i] = {
						"index":i,
						"name":achievements[i]["name"],
						"status":u"완료" if achievements[i]["status"]!=-1 else u"미완료",
					}
				
				for ui in userInfos:
					if ui.get("titles"):
						maxCol = max(maxCol, len(ui["titles"])) 
				
				storageCharacters = getStorageData("characters")
				characters = ndb.get_multi(user.character_keys)
				for c in characters:
					charInfos.append(
						{
							"index":len(charInfos),
							"name":storageCharacters[c.character_id-1]["name"],
							"level":c.level,
							"exp":c.exp,
							"point":c.point,
							"cooltimes":c.cooltimes(datetime.now()),
						}
					)
		else:
			userId = ""
		
		template = jinja_environment.get_template('templates/cs.html')
		self.response.out.write(
			template.render(
				logoutUrl=logoutUrl,
				adminName=adminName,
				userId=userId,
				userInfos=userInfos,
				characterInfos=charInfos,
				d3=d3,
				w3=w3,
				achievements=achievements,
				maxCol=maxCol,
			)
		)
		return
	
class EditUserHandler(webapp2.RequestHandler):
	def get(self, userId=None):
		if not users.get_current_user() or not users.is_current_user_admin():
			self.redirect(users.create_login_url(self.request.uri))
			return
		
		template = jinja_environment.get_template('templates/cs_edit_user.html')
		self.response.out.write(
			template.render(
				userId=userId,
			)
		)
		return
	
	def post(self, userId=None):
		if not users.get_current_user() or not users.is_current_user_admin():
			self.redirect(users.create_login_url(self.request.uri))
			return
		
		adminName = users.get_current_user().nickname()
		
		index = -1
		flag = 1
		
		for i in range(10):
			if self.request.POST.has_key('add%d' % i):
				index = i
				flag = 1
				break
			if self.request.POST.has_key('remove%d' % i):
				index = i
				flag = 2
				break
		
		userId = int(userId)
		result = None
		rewardTitle = cgi.escape(self.request.POST['reward_title']) if self.request.POST.get('reward_title') else u"마시마로팍팍(관리자)"
		inputNames = ['cash', 'coin', 'bout']
		if index in [REWARD_CASH, REWARD_COIN, REWARD_BOUT]:
			if flag == 1:
				amount = int(self.request.get(inputNames[index]))
				user = User.get_by_id(userId)
				if amount > 0 and user:
					addInbox(user, rewardTitle, rewardTitle, index, amount, True)
					result = (u"<h5 style=\"color:black;\">성공(%s 수신함으로 지급되었습니다.)</h5>" % rewardName(index, amount))
					CSManageLog(admin_name=adminName, user_id=userId, action=index, value=amount, desc=cgi.escape(self.request.get('memo'))).put()
			elif flag == 2:
				amount = int(self.request.get(inputNames[index]))
				user = User.get_by_id(userId)
				if amount > 0 and user:
					if eval("user.{0} >= {1}".format(inputNames[index], amount)):
						exec("user.{0} -= {1}".format(inputNames[index], amount))
						user.put()
						result = (u"<h5 style=\"color:blue;\">성공(%s 즉시 회수 됨 - %d개남음)</h5>" % (rewardName(index, amount), eval("user.{0}".format(inputNames[index])),))
						CSManageLog(admin_name=adminName, user_id=userId, action=index + 100, value=amount, desc=cgi.escape(self.request.get('memo'))).put()
							
					else:
						result = (u"<h5 style=\"color:red;\">실패(%s,부족 - %d개)</h5>" % (rewardName(index, 0), eval("user.{0}".format(inputNames[index])),))
		if result is None:
			result = u"<h5 style=\"color:red;\">실패(입력값 오류 또는 사용자 찾을 수 없음)</h5>"

		template = jinja_environment.get_template('templates/cs_edit_user.html')
		self.response.out.write(
			template.render(
				userId=userId,
				result=result,
			)
		)
		return

class UserLogsHandler(webapp2.RequestHandler):
	def render(self, userId, cursor, reversed, toggled):
		logoutUrl = users.create_logout_url(self.request.uri)
		adminName = users.get_current_user().nickname()
		
		total=0
		prev=False
		next=False
		more=False
		userLogs = []
		fromDay = None
		selectedAction = -1
		
		def description(actionId, jsonLog):
			log = json.loads(jsonLog)
			if actionId in [ACTION_REGISTER,ACTION_LOGIN,]:
				return u"플랫폼:{0} / 보유복숭아:{1} /  보유코인:{2} / 보유당근:{3} / 일일포인트:{4} / 출석일수:{5} / 푸시제한:{6} / 당근선물제한:{7} / 주간총점수:{8} / 랭킹:{9}".format(
						(u"IOS" if log["platform"] == PLATFORM_IOS else u"PlayStore"), 
						log["cash"], log["coin"], log["bout"],
						log["udpoint"], log["stamp"],
						log["blocks"][0], log["blocks"][1],
						log["score"],
						log["rank"])
			elif actionId == ACTION_APP_UPDATE:
				return u"플랫폼:{0} / 버전:{1}".format((u"IOS" if log["platform"] == PLATFORM_IOS else u"PlayStore"), log['version'])
			elif actionId == ACTION_ASSET_UPDATE:
				return u"플랫폼:{0} / 버전:{1}".format((u"IOS" if log["platform"] == PLATFORM_IOS else u"PlayStore"), log['version'])
			elif actionId == ACTION_RESTRICTED:
				return u"메세지:{0} / 기간:{1}".format(log['msg'], log['until'])
			elif actionId == ACTION_APPFRIENDS:
				return u"랭킹:{0} / 친구수:{1}".format(log['rank'], log['friendCount'])
			elif actionId == ACTION_READY_IAP:
				return u"복숭아아이디:{0} / 복숭아개수:{1} / Payload:{2}".format(
							log["id"],
							log["cash"],
							log["payload"])
			elif actionId == ACTION_IAP:
				return u"상태:{0} / 보유복숭아:{1} / 추가된복숭아:{2} / 친구아이디:{3}".format(
							log["status"],
							log["ucash"],
							log["cash"],
							log.get("friend")
							)
			elif actionId == ACTION_BUY_COIN:
				return u"상태:{0} / 코인아이디:{1} / 보유복숭아:{2} / 보유코인:{3} / 사용복숭아:{4} / 추가코인:{5}".format(
							log["status"],
							log["id"], 
							log["ucash"],
							log["ucoin"], 
							log["cash"],
							log["coin"])
			elif actionId == ACTION_BUY_BOUT:
				return u"상태:{0} / 당근아이디:{1} / 보유복숭아:{2} / 보유당근:{3} / 사용복숭아:{4} / 추가당근:{5}".format(
							log["status"], 
							log["id"], 
							log["ucash"],
							log["ubout"], 
							log["cash"],
							log["bout"])
			elif actionId == ACTION_SEASON_REWARD:
				return u"랭킹:{0} / 점수:{1} / 친구수:{2} / 보상코인:{3} / 보유코인:{4}".format(
							log["rank"], 
							log["score"],
							log["friendCount"], 
							log["coin"],
							log["ucoin"])
			elif actionId == ACTION_BLOCK:
				return u"푸시제한:{0} / 당근선물제한:{1}".format(log["blocks"][0], log["blocks"][1])
			elif actionId == ACTION_TUTORIAL:
				return u"추가복숭아:{0} / 보유복숭아:{1} / 튜토리얼들:{2}".format(log["cash"],log["ucash"],log["tutorials"])
			elif actionId == ACTION_READY:
				return u"인증키:{0}".format(log["authorKey"])
			elif actionId == ACTION_BOAST:
				return u"상태:{0} / 인증키:{1} / 입력키:{2} / 보유일일포인트:{3} / 추가된일일포인트:{4}".format(
							log["status"],
							log["authorKey"],
							log["inputKey"],
							log["udpoint"],
							log["dpoint"])
			elif actionId == ACTION_SEND_BOUT:
				return u"상태:{0} / 친구아이디:{1} / 보유일일포인트:{2} / 추가된일일포인트:{3}".format(
							log["status"],
							log["id"],
							log["udpoint"],
							log["dpoint"])
			elif actionId == ACTION_REQUEST_BOUT:
				return u"상태:{0} / 친구아이디:{1}".format(
							log["status"],
							log["id"])
			elif actionId == ACTION_INVITE_APP:
				return u"상태:{0} / 친구아이디:{1} / 누적초대수:{2} / 보상:{3}".format(
							log["status"],
							log["id"],
							log["count"],
							rewardName(log['reward'],log['rewardArg']))
			elif actionId == ACTION_BUY_CHARACTER:
				return u"상태:{0} / 캐릭터아이디:{1} / 보유복숭아:{2} / 사용된복숭아:{3} / 보유캐릭터들:{4}".format(
							log["status"],
							log["id"], 
							log["ucash"], 
							log["cash"],
							",".join(characterInfos(log['characters'])))
			elif actionId == ACTION_EQUIP_CHARACTER:
				return u"착용캐릭터:{0} / 보유캐릭터들:{1}".format(
							characterName(log['id']),
							",".join(characterInfos(log['characters'])))
			elif actionId == ACTION_ADOPT_CHARACTER:
				return u"상태:{0} / 친구아이디:{1} / 캐릭터:{2}".format(
							log['status'],
							log['id'],
							characterName(log['characterId']))
			elif actionId == ACTION_FEED_CHARACTER:
				return u"상태:{0} / 액션:{1} / 내캐릭터:{2} / 친구아이디:{3} / 신규달성미션:{4}".format(
							log['status'],
							log['action'],
							log['self'],
							log["id"],
							log['mission'])
			elif actionId == ACTION_BUFF:
				return u":버프:{0} / 신규달성미션:{1}".format(
							characterName(log['id']),
							log['mission'])
			elif actionId == ACTION_CLEAR_COOLTIME:
				return u":캐릭터:{0} / 사용된복숭아:{1} / 보유복숭아:{2}".format(
							characterName(log['id']),
							log['cash'],
							log['ucash'])
			elif actionId == ACTION_EQUIP_ITEM:
				return u"게임:{0} / 슬롯인덱스:{1} / 필요코인:{2} / 보유코인:{3} / 장착아이템들:{4}".format(
							gameName(log["game"]),
							log["idx"],
							log["coin"],
							log["ucoin"],
							log["items"])
			elif actionId == ACTION_GACHA_ITEM:
				return u"상태:{0} / 게임:{1} / 소모코인:{2} / 필요코인:{3} / 보유코인:{4} / 장착아이템들:{5}".format(
							log["status"],
							gameName(log["game"]),
							log["coin"],
							log["ncoin"],
							log["ucoin"],
							log["items"])
			elif actionId == ACTION_USE_DAILYPOINT:
				return u"보상:{0} / 보유복숭아:{1} / 보유코인:{2} / 보유당근:{3}".format(
							rewardName(log["reward"], log["amount"]),
							log["ucash"],
							log["ucoin"],
							log["ubout"])
			elif actionId == ACTION_GAME_START:
				return u"사용된코인:{0} / 보유코인:{1} / 사용된당근:{2} / 보유당근:{3} / 보유복숭아:{4} / 장착아이템들:{5} / 버프:{6} / 인증키:{7}".format(
							log["coin"],
							log["ucoin"],
							log["bout"],
							log["ubout"],
							log["ucash"],
							log["items"],
							characterName(log["buffId"]),
							log["authorKey"])
			elif actionId == ACTION_GAME_RESULT:
				return u"게임:{0} / 보유복숭아:{1} / 보유코인:{2} / 보유당근:{3} / 신규달성미션:{4} / 콤보:{5} / 피버:{6} / 획득코인:{7} / 획득경험치:{8} / 보너스점수:{9} / 점수:{10} / 레벨업:{11} / 신규달성미션:{12} / 장착캐릭터:{13} / 일일포인트:{14}".format(
							gameName(log["game"]),
							log["cash"],
							log["coin"],
							log["bout"],
							len(log["missions"]),
							log["combo"],
							log["fever"],
							log["obtainCoin"],
							log["obtainExp"],
							log["bonusScore"],
							log["score"],
							log["levelUp"],
							len(log["missions"]),
							characterInfo(log["character"]),
							log.get("udpoint"))
			elif actionId == ACTION_USE_CONTINUE:
				return u"상태:{0} / 사용복숭아:{1} / 보유복숭아:{2}".format(
							log["status"],
							log["cash"],
							log["ucash"])
			elif actionId == ACTION_CONFIRM_INBOX:
				names = []
				for r in log["rewards"]:
					names.append(rewardName(r["reward"], r["amount"]))
				return u"보유복숭아:{0} / 보유코인:{1} / 보유당근:{2} / 받은물품들:{3}".format(
							log["ucash"],
							log["ucoin"],
							log["ubout"],
							",".join(names))
			elif actionId == ACTION_UNREGISTER:
				return u"보유복숭아:{0} / 보유코인:{1} / 보유당근:{2}".format(
							log["ucash"],
							log["ucoin"],
							log["ubout"])
			return jsonLog

		user = User.get_by_id(int(userId)) if userId else None
		
		if userId and user:
			qry = UserLog.query(UserLog.user_id == user.key.id(), ancestor=user.key)
		elif not userId:
			qry = UserLog.query()
		else:
			qry = None
		
		if qry:
			next = True
			prev = True
			
			if reversed==False and cursor==None:
				prev = False
			
			try:
				fromDay = replace_timezone(datetime.strptime(self.request.POST.get('fromDay'), "%Y-%m-%d"))
				fromDay = datetime(fromDay.year, fromDay.month, fromDay.day, 23,59,59)
			except:
				fromDay = None
			try:
				selectedAction = int(self.request.POST.get('actions'))
			except:
				selectedAction = -1
			
			if fromDay:
				qry = qry.filter(UserLog.created_at<fromDay)
			if selectedAction!=-1:
				qry = qry.filter(UserLog.action==selectedAction)
			logging.info('selectedAction = %s' % selectedAction)
			total = 0
			if reversed:
				qry = qry.order(UserLog.created_at)
			else:
				qry = qry.order(-UserLog.created_at)
			
			if toggled: # toggled==True: 한번 더 쿼리를 해서, 진짜로 넘어가게 한다.
				results, cursor, more = qry.fetch_page(int(self.request.POST['count']), start_cursor=cursor)
			results, cursor, more = qry.fetch_page(PAGE, start_cursor=cursor)
			
			if reversed and more==False:
				prev = False
			if reversed==False and more==False:
				next = False
			for ul in results:
				desc = description(ul.action, ul.log)
				userLogs.append(
					{
						"index":len(userLogs),
						"id":ul.user_id,
						"action":ACTION_NAMES[ul.action],
						"log":desc,
						"created_at":replace_timezone(ul.created_at, 'Asia/Seoul').strftime('%Y-%m-%d %H:%M:%S'),
					}
				)
		userLogs = sorted(userLogs, key=itemgetter('created_at'), reverse=True)
		
		if userId is None:
			userId = ""
		
		template = jinja_environment.get_template('templates/cs_user_logs.html')
		self.response.out.write(
			template.render(
				logoutUrl=logoutUrl,
				adminName=adminName,
				userId=userId,
				userLogs=userLogs,
				total=total,
				reversed=reversed,
				prev=prev,
				next=next,
				cursor=cursor.urlsafe() if cursor else None,
				more=more,
				count=len(userLogs),
				fromDay=replace_timezone(fromDay,'Asia/Seoul').strftime("%Y-%m-%d") if fromDay else "",
				selectedAction=selectedAction,
				actions=[a for a in ACTION_NAMES],
			)
		)
		return
		
	def get(self, userId=None):
		if not users.get_current_user() or not users.is_current_user_admin():
			self.redirect(users.create_login_url(self.request.uri))
			return
		
		self.render(userId, None, False, False)

	def post(self, userId=None):
		if not users.get_current_user() or not users.is_current_user_admin():
			self.redirect(users.create_login_url(self.request.uri))
			return

		cursor = None
		reversed = False
		toggled = False
		
		if self.request.POST.has_key('_prev'):
			cursor = Cursor(urlsafe=self.request.POST['cursor']) if self.request.POST.get('cursor') != '' else None
			if not eval(self.request.POST['reversed']):
				cursor = cursor.reversed()
				toggled = True
			reversed = True
		elif self.request.POST.has_key('_next'):
			cursor = Cursor(urlsafe=self.request.POST['cursor']) if self.request.POST.get('cursor') != '' else None
			if eval(self.request.POST['reversed']):
				cursor = cursor.reversed()
				toggled = True
			reversed = False
		self.render(userId, cursor, reversed, toggled)
		
class CSAdminLogsHandler(webapp2.RequestHandler):
	def render(self, cursor, reversed, toggled):
		logoutUrl = users.create_logout_url(self.request.uri)
		adminName = users.get_current_user().nickname()

		next = True
		prev = True
		
		if reversed==False and cursor==None:
			prev = False
		
		qry = CSManageLog.query()
		if reversed:
			qry = qry.order(CSManageLog.created_at)
		else:
			qry = qry.order(-CSManageLog.created_at)
		total = CSManageLog.query().count()
		
		if toggled: # toggled==True: 한번 더 쿼리를 해서, 진짜로 넘어가게 한다.
			results, cursor, more = qry.fetch_page(int(self.request.POST['count']), start_cursor=cursor)
		results, cursor, more = qry.fetch_page(PAGE, start_cursor=cursor)
		
		if reversed and more==False:
			prev = False
		if reversed==False and more==False:
			next = False
		
		logs = []
		
		def actionName(action, value):
			if action in [REWARD_CASH, REWARD_COIN, REWARD_BOUT]:
				return ("%s %s" % (rewardName(action, value), u"지급",))
			elif action in [act + 100 for act in [REWARD_CASH, REWARD_COIN, REWARD_BOUT]]:
				return ("%s %s" % (rewardName(action - 100, value), u"회수",))
		
		for log in results:
			logs.append(
				{
					"index":len(logs),
					"id":log.key.id(),
					"userId":log.user_id,
					"admin":log.admin_name,
					"action":actionName(log.action, log.value),
					"data":log.value,
					"desc":log.desc,
					"datetime":replace_timezone(log.created_at, 'Asia/Seoul').strftime('%Y-%m-%d %H:%M:%S'),
				}
			)
		
		logs = sorted(logs, key=itemgetter('datetime'), reverse=True)
		
		template = jinja_environment.get_template('templates/cs_admin_logs.html')
		self.response.out.write(
			template.render(
				logoutUrl=logoutUrl,
				adminName=adminName,
				logs=logs,
				total=total,
				reversed=reversed,
				prev=prev,
				next=next,
				cursor=cursor.urlsafe() if cursor else None,
				more=more,
				count=len(logs),
			)
		)
		
	def get(self):
		if not users.get_current_user() or not users.is_current_user_admin():
			self.redirect(users.create_login_url(self.request.uri))
			return
		
		self.render(None, False, False)
		
	def post(self):
		if not users.get_current_user() or not users.is_current_user_admin():
			self.redirect(users.create_login_url(self.request.uri))
			return

		cursor = None
		reversed = False
		toggled = False
		
		if self.request.POST.has_key('_prev'):
			cursor = Cursor(urlsafe=self.request.POST['cursor']) if self.request.POST.get('cursor') != '' else None
			if not eval(self.request.POST['reversed']):
				cursor = cursor.reversed()
				toggled = True
			reversed = True
		elif self.request.POST.has_key('_next'):
			cursor = Cursor(urlsafe=self.request.POST['cursor']) if self.request.POST.get('cursor') != '' else None
			if eval(self.request.POST['reversed']):
				cursor = cursor.reversed()
				toggled = True
			reversed = False
		self.render(cursor, reversed, toggled)

class StatisticsHandler(webapp2.RequestHandler):
	@staticmethod
	def getPlatformCounters(start, end, stat_format, param=None):
		name = stat_format.format(PLATFORM_IOS, param)
		iosJsonData = statistics.getRangeCount(name, start, end)
		name = stat_format.format(PLATFORM_PLAYSTORE, param)
		psJsonData = statistics.getRangeCount(name, start, end)
		
		return {
			"ios":iosJsonData,
			"playstore":psJsonData,
		}
	
	@staticmethod
	def getMultiplePlatformCounters(start, end, stat_format, length):
		result = {}
		result["range"] = length
		result['ios'] = []
		result['playstore'] = []
		result['ios_total'] = 0
		result['playstore_total'] = 0
		
		ios_data = {}
		ps_data = {}
		for i in range(result["range"]):
			iosJsonData, psJsonData = StatisticsHandler.getPlatformCounters(start, end, stat_format, i + 1)
			for ios in iosJsonData['counters']:
				if not ios_data.has_key(ios['stamp']):
					ios_data[ios['stamp']] = {}
				ios_data[ios['stamp']]["count{0}".format(i)] = ios["count"]
			result['ios_total'] += iosJsonData['total']
			for ps in psJsonData['counters']:
				if not ps_data.has_key(ps['stamp']):
					ps_data[ps['stamp']] = {}
				ps_data[ps['stamp']]["count{0}".format(i)] = ps["count"]
			result['playstore_total'] += psJsonData['total']
		
		keys = ios_data.keys()
		keys.sort()
		for key in keys:
			v = ios_data[key]
			v['stamp'] = key
			result['ios'].append(v)
			
		keys = ps_data.keys()
		keys.sort()
		for key in keys:
			v = ps_data[key]
			v['stamp'] = key
			result['playstore'].append(v)
		return result
	
	def ratioGraphRender(self, logoutUrl, adminName, kind):
		name = None
		delta = int(self.request.get('delta'))
		
		
		ratioStat = RatioStatistics.query().order(-RatioStatistics.stamp).get()
		if ratioStat is None:
			return
		
		stamp = str(ratioStat.stamp)
		stamp = datetime(int(stamp[:4]),int(stamp[4:6]), int(stamp[6:]))
		stamp += timedelta(days=delta)
		stamp = (int(stamp.strftime('%Y%m%d')))
		
		ratioStat = RatioStatistics.query(RatioStatistics.stamp==stamp).get()
		if ratioStat is None:
			return
		
		totalUsers = ratioStat.user_count
		activeUsers = 0
		
		if kind=='gameplays':
			values = ratioStat.user_games
			name = u"게임 횟수 분포"
			names = ['1 game', '2 games', '3~10 games', '11~50 games', '51~200 games', '200 games or more'] 
			activeUsers = (values[0]+values[1])
			values = [values[0], values[1]-values[2], values[2]-values[3], values[3]-values[4], values[4]-values[5], values[5]]
		
		stamp= str(stamp)
		date = "{0}-{1}-{2}".format(stamp[:4], stamp[4:6], stamp[6:])
		data =[{"name":names[i], "value":values[i]} for i in range(len(names))] 
		
		template = jinja_environment.get_template('templates/statistics_distribution.html')
		self.response.out.write(
			template.render(
				logoutUrl=logoutUrl,
				adminName=adminName,
				name=name,
				date=date,
				totalUsers=totalUsers,
				activeUsers=activeUsers,
				data=json.dumps(data),
				delta=delta,
				ratio=kind,
			)
		)
		
	def accrueGraphRender(self, logoutUrl, adminName):
		name = cgi.escape(self.request.get('name'))
		delta = int(self.request.get('delta'))
		term = self.request.get('term')
		timezone = self.request.get('timezone')
		if timezone is None:
			timezone = '0'
			
		now = datetime.now()
		
		start = replace_timezone(now, 'Asia/Seoul')
		stamps = []
		stampNames = []
		stampTitle = None
		if term=='hourly':
			start += timedelta(days=delta)
			start = datetime(start.year, start.month, start.day, 0, 0, 0)
			end = datetime(start.year, start.month, start.day, 23, 0, 0)
			stampTitle = start.strftime('%Y/%m/%d ~ ') + end.strftime('%Y/%m/%d')
			while start<=end:
				stampNames.append(int(start.strftime('%H')))
				if timezone=='1':
					stamps.append(int((start+timedelta(hours=-16)).strftime('%Y%m%d%H')))
				else:
					stamps.append(int(start.strftime('%Y%m%d%H')))
				start += timedelta(hours=1)
		elif term=='daily':
			start += timedelta(days = (delta*7))
			start = datetime(start.year, start.month, start.day, 0, 0, 0)
			start += timedelta(days = -6)
			end = start + timedelta(days = 6)
			stampTitle = start.strftime('%Y/%m/%d ~ ') + end.strftime('%Y/%m/%d')
			while start<=end:
				stampNames.append(int(start.strftime('%d')))
				stamps.append(int(start.strftime('%Y%m%d%H')))
				start += timedelta(days=1)
		elif term=='weekly':
			start += timedelta(days = (delta*7))
			start = datetime(start.year, start.month, 1, 0, 0, 0)
			if start.month==12:
				end = datetime(start.year+1, 1, 1, 0, 0, 0)
			else:
				end = datetime(start.year, start.month+1, 1, 0, 0, 0)
			stampTitle = start.strftime('%Y/%m/%d ~ ') + end.strftime('%Y/%m/%d')
			week = 1
			while start<=end:
				stampNames.append(week)
				stamps.append(int(start.strftime('%Y%m%d%H')))
				start += timedelta(days=7)
				week += 1
		fields = str(self.request.get('fields')).split(',')
		
		counts = []
		maxCount = 0
		if len(fields)==1:
			for stamp in stamps:
				stat = Statistics.query(Statistics.stamp==stamp).get()
				if stat is None:
					counts.append(maxCount)
				else:
					count = eval("stat.{0}".format(fields[0]))
					maxCount = max(maxCount, count)
					counts.append(count)
		elif len(fields)==2:
			for stamp in stamps:
				stat = Statistics.query(Statistics.stamp==stamp).get()
				if int(fields[1])<0:
					if stat is None:
						counts.append(maxCount)
					else:
						count = sum(eval("stat.{0}".format(fields[0])))
						maxCount = max(maxCount, count)
						counts.append(count)
				else:
					if stat is None:
						counts.append(maxCount)
					else:
						count = eval("stat.{0}[{1}]".format(fields[0], int(fields[1])))
						maxCount = max(maxCount, count)
						counts.append(count)
		
		minCount = min(counts)
		maxCount = max(counts)
		
		template = jinja_environment.get_template('templates/statistics_curve.html')
		self.response.out.write(
			template.render(
				logoutUrl=logoutUrl,
				adminName=adminName,
				name=name,
				minCount=minCount,
				maxCount=maxCount,
				stampNames=stampNames,
				stampTitle=stampTitle,
				counts=counts,
				fields=str(self.request.get('fields')),
				term=term,
				delta=delta,
				timezone=timezone,
			)
		)
	
	def subst_lists(self, list1, list2):
		if list1 is None:
			list1 = []
		if list2 is None:
			list2 = []
		count = max(len(list1), len(list2))
		result = []
		for i in range(count):
			result.append((list1[i] if i<len(list1) else 0) - (list2[i] if i<len(list2) else 0))
		return result
		
	def subst_xlists(self, list1, list2):
		if list1 is None:
			list1 = []
		while len(list1)<GAME_COUNT:
			list1.append(UsedItem())
		if list2 is None:
			list2 = []
		while len(list2)<GAME_COUNT:
			list2.append(UsedItem())
		result = []
		for i in range(GAME_COUNT):
			item = UsedItem()
			item.item0 = list1[i].item0-list2[i].item0
			item.item1 = list1[i].item1-list2[i].item1
			item.item2 = list1[i].item2-list2[i].item2
			item.item3 = list1[i].item3-list2[i].item3
			result.append(item)
		return result

	def accrueTermRender(self, logoutUrl, adminName, fromDay, toDay, export=False):
		fromStamp=int(fromDay.replace('-','')+"00")
		toStamp=int(toDay.replace('-','')+"23")
		
		firstStatistics = Statistics.query(Statistics.stamp==fromStamp).get()
		if firstStatistics is None:
			firstStatistics = Statistics.query().order(Statistics.stamp).get()
		lastStatistics = Statistics.query(Statistics.stamp==toStamp).get()
		if lastStatistics is None:
			lastStatistics = Statistics.query().order(-Statistics.stamp).get()
		
		stat = Statistics()
		
		if lastStatistics and firstStatistics:
			for attr in dir(Statistics):
				if attr.startswith('i_') or attr.startswith('p_'):
					logging.info("attr = %s" % attr)
					if type(eval("stat.{0}".format(attr)))==list:
						list1 = eval("lastStatistics.{0}".format(attr))
						list2 = eval("firstStatistics.{0}".format(attr))
						if attr.find('use_items')>0:
							delta = self.subst_xlists(list1, list2)
						else:
							delta = self.subst_lists(list1, list2)
						exec("stat.{0} = {1}".format(attr, delta))
						#eval("stat.{0}.extend(map(int.__sub__, lastStatistics.{0}, firstStatistics.{0}))".format(attr))
					else:
						if attr.find('_dau')==1:
							exec("stat.{0} = (lastStatistics.{0})".format(attr))
						else:
							exec("stat.{0} = (lastStatistics.{0} - firstStatistics.{0})".format(attr))
		template = jinja_environment.get_template('templates/statistics.html')
		self.response.out.write(
			template.render(
				logoutUrl=logoutUrl,
				adminName=adminName,
				statistics=stat,
				fromDay=fromDay,
				toDay=toDay,
				date=replace_timezone(datetime.now(), 'Asia/Seoul').strftime('%Y-%m-%d'),
			)
		)
		
	def post(self, kind=None):
		if not users.get_current_user() or not users.is_current_user_admin():
			self.redirect(users.create_login_url(self.request.uri))
			return
		
		logoutUrl = users.create_logout_url(self.request.uri)
		adminName = users.get_current_user().nickname()
		
		fromDay = self.request.get('fromDay')
		toDay = self.request.get('toDay')
			
		if self.request.POST.has_key('_search'):
			if fromDay or toDay:
				self.accrueTermRender(logoutUrl, adminName, fromDay, toDay)
			else:
				self.redirect('/cs/statistics/')
		elif self.request.POST.has_key('_export'):
			if fromDay or toDay:
				self.accrueTermRender(logoutUrl, adminName, fromDay, toDay, True)
			else:
				self.redirect('/cs/statistics/')
		else:
			self.redirect('/cs/statistics/')
			
	def get(self):
		if not users.get_current_user() or not users.is_current_user_admin():
			self.redirect(users.create_login_url(self.request.uri))
			return
		
		logoutUrl = users.create_logout_url(self.request.uri)
		adminName = users.get_current_user().nickname()
		
		if self.request.get('term') in ['hourly', 'daily', 'weekly',]:
			self.accrueGraphRender(logoutUrl, adminName)
			return
		elif self.request.get('ratio'):
			self.ratioGraphRender(logoutUrl, adminName, self.request.get('ratio'))
			return
		
		now = replace_timezone(datetime.now(), 'Asia/Seoul')
		if now.hour==0:
			fromDay = (now-timedelta(days=1)).strftime('%Y-%m-%d')
		else:
			fromDay = now.strftime('%Y-%m-%d')
		toDay = now.strftime('%Y-%m-%d')
		self.accrueTermRender(logoutUrl, adminName, fromDay, toDay)

class AbusersHandler(webapp2.RequestHandler):
	def get(self, userId=None):
		if not users.get_current_user() or not users.is_current_user_admin():
			self.redirect(users.create_login_url(self.request.uri))
			return
		
		logoutUrl = users.create_logout_url(self.request.uri)
		adminName = users.get_current_user().nickname()
		
		abusers = []
		restricts = []
		now = datetime.now()
		platformNames = [None, "IOS", "PlayStore", "T store"]
		for abuser in Abuser.query(Abuser.total > 0).order(-Abuser.total).fetch(300, read_policy=ndb.EVENTUAL_CONSISTENCY):
			u = User.get_by_id(abuser.key.id())
			if u:
				abusers.append(
					{
						"id":abuser.key.id(),
						"platform":platformNames[u.platform_id],
						"total":abuser.total,
						"network":abuser.network_hack,
						"memory":abuser.memory_hack,
						"binary":abuser.binary_hack,
						"device":abuser.device_hack,
						"iap":abuser.iap_hack,
						"iapFail":abuser.iap_fail,
					}
				)
		for rest in UserRestricted.query(UserRestricted.expired_at > now).order(-UserRestricted.expired_at).fetch(1000):
			restricts.append(
				{
					"id":rest.user_id,
					"message":rest.message,
					"expiredAt":replace_timezone(rest.expired_at, 'Asia/Seoul').strftime('%Y-%m-%d %H:%M:%S'),
					"createdAt":replace_timezone(rest.created_at, 'Asia/Seoul').strftime('%Y-%m-%d %H:%M:%S'),
				}
			)
	
		restrict = None
		user = User.get_by_id(int(userId)) if userId else None
		if user:
			r = UserRestricted.query(UserRestricted.user_id==user.key.id(), ancestor=UserRestricted.ancestorKey(user)).get()
			restrict = {
				"id":r.user_id,
				"message":r.message,
				"expired_date_at":replace_timezone(r.expired_at,'Asia/Seoul').strftime('%Y-%m-%d') if r.expired_at else "",
				"expired_time_at":replace_timezone(r.expired_at,'Asia/Seoul').strftime('%H:%M:%S') if r.expired_at else "",
			}
			
		template = jinja_environment.get_template('templates/statistics_abuser.html')
		self.response.out.write(
			template.render(
				logoutUrl=logoutUrl,
				adminName=adminName,
				abusers=abusers,
				restrict=restrict,
				restricts=restricts,
			)
		)
	
	def post(self):
		if not users.get_current_user() or not users.is_current_user_admin():
			self.redirect(users.create_login_url(self.request.uri))
			return
		
		logoutUrl = users.create_logout_url(self.request.uri)
		adminName = users.get_current_user().nickname()
		
		userId = int(cgi.escape(self.request.get('user_id')))
		message = cgi.escape(self.request.get('message'))
		expired_date_at = cgi.escape(self.request.get('expired_date_at')) if self.request.get('expired_date_at') else None
		expired_time_at = cgi.escape(self.request.get('expired_time_at')) if self.request.get('expired_time_at') else None
		expired_at = replace_timezone(datetime.strptime(expired_date_at+expired_time_at, "%Y-%m-%d%H:%M:%S")) if expired_date_at and expired_time_at else None
		
		user = User.get_by_id(userId)
		if user and expired_at and message:
			userRestricted = UserRestricted.query(UserRestricted.user_id==user.key.id(), ancestor=UserRestricted.ancestorKey(user)).get()
			if userRestricted is None:
				userRestricted = UserRestricted(parent=UserRestricted.ancestorKey(user), user_id=user.key.id())
			userRestricted.message=message
			userRestricted.expired_at=expired_at
			userRestricted.put()
		
		time.sleep(2)
		self.redirect('/cs/abusers/')
		return
